import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Point2D.Double;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.TreeMap;


public class MovableTransport implements Runnable {
	private DiGraph roads;
	private Point2D.Double location;
	private Point2D destination;
	private int velocity = 5;
	private MapPanel panel = null;
	private Random generator = new Random();
	private boolean active = true;
	private Thread thread;
	
	private LineIterator lineIter;
	private Iterator<Vertex> vertIter;
	
	public MovableTransport(TreeMap<String, Road> roadMap) {
		roads = new DiGraph();
		location = new Point2D.Double();
		destination = new Point2D.Double();
		
		for (Road road : roadMap.values()) {
			for (Line2D.Double sect : road.getSections()) {
				Vertex v1, v2;
				if ((v1 = roads.getVertex(sect.getP1())) == null)
					v1 = roads.createVertex(sect.getP1());
				if ((v2 = roads.getVertex(sect.getP2())) == null)
					v2 = roads.createVertex(sect.getP2());
				roads.addEdge(v1, v2, sect.getP1().distance(sect.getP2()));
				roads.addEdge(v2, v1, sect.getP1().distance(sect.getP2()));
			}
		}
		
		
	}

	public Point2D getLocation() {
		return location;
	}
	
	public List<Vertex> getShortestPath() {
		return roads.getShortestPath();
	}
	
	public Point2D getVertexPoint(int num) {
		return roads.getVertex(num).getPoint2D();
	}
	
	public void setPanel(MapPanel panel) {
		this.panel = panel;
	}
	
	public void generatePath() {
		roads.getShortestPath().clear();
		// Set location to destination or generate a new location
		if (roads.getNearest(destination, 100) != null)
			location.setLocation(destination);
		else
			location.setLocation(roads.getVertex(generator.nextInt(roads.getVertexNo()+1)).getPoint2D());
		
		destination = roads.getVertex(generator.nextInt(roads.getVertexNo() + 1)).getPoint2D();
		roads.dijkstra(location, 100);		
		roads.printPath(roads.getPath(destination, 100, "m"));
	}
	
	public void setInactive() {
		active = false;
	}
	
	public void start() {
		thread = new Thread(this);
		thread.start();
	}
	
	public void move() {
		// No path to iterate
		if (roads.getShortestPath().size() == 0)
			return;
		
		// Generate path and create vertex iterator
		if (vertIter == null) {
			generatePath();
			vertIter = roads.getShortestPath().iterator();
		}
		
		// End of the path create another
		if (!vertIter.hasNext()) {
			generatePath();
			vertIter = roads.getShortestPath().iterator();
		}
		
		// Generate section iterator
		if (lineIter == null) {
			location.setLocation(vertIter.next().getPoint2D());
			lineIter = new LineIterator(new Line2D.Double(location, vertIter.next().getPoint2D()));
		}
		
		// End of line get next section
		if (!lineIter.hasNext())
			lineIter = new LineIterator(new Line2D.Double(location, vertIter.next().getPoint2D()));
		
		location.setLocation(lineIter.next());
	}
	
	/**
	 * 
	 */
	public void run() {
		if (panel == null)
			return;
		
		while (active) {
			generatePath();
			//System.out.println("Generated new path starting at " + location.toString());
			for (Vertex vert : roads.getShortestPath()) {
				
				Line2D.Double path = new Line2D.Double(location, vert.getPoint2D());
				LineIterator line = new LineIterator(path);
				
				while (line.hasNext()) {
					try {
						location.setLocation(line.next());
						//System.out.println(location.toString());
						panel.repaint();
						Thread.sleep(velocity);				
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
				}
				//System.out.println("Arrived at vertex " + vert.getPoint2D().toString());
			}
			//System.out.println("Arrived at destination " + destination.toString());
		}
	}
}
